#include <cmath>
#include <cstdlib> 
#include <ctime> 
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>

typedef std::vector<std::string> Lines;
typedef std::vector<std::string> Strings;
typedef std::vector<Lines> Files;

int numberOfAttributes = 0;

void explode(Strings& p_results,
			 const std::string& p_string,
			 const std::string& p_seperator)
{
	std::string temp = p_string;
	size_t found = temp.find(p_seperator);
	while (found != std::string::npos)
	{
		if (found > 0)
		{
			p_results.push_back(temp.substr(0,found));
		}
		temp = temp.substr(found + p_seperator.length());
		found = temp.find(p_seperator);
	}
	if (temp.length() > 0)
	{
		p_results.push_back(temp);
	}
}

bool getFileLines(Lines& p_lines, const char* p_filename)
{
	std::ifstream filestream(p_filename, std::ios::binary);
	
	if(filestream.fail())
		std::cout << "Failed to open: " << p_filename;

	// Get file length.
	filestream.seekg (0, std::ios::end);
	unsigned int length = static_cast<unsigned int>(filestream.tellg());
	filestream.seekg (0, std::ios::beg);

	char* data = new char[length];
	filestream.read(data, length);

	unsigned int start = 0;
	bool comment = false;
	unsigned int i = 0;
	for (; i < length; ++i)
	{
		char letter = data[i];
		if (i == start && letter == '#')
		{
			comment = true;
		}
		if (letter == '\n' || letter == '\r')
		{
			if (comment == false && i != start)
			{
				if (start + (i - start) > length)
					std::cout << "Index out of range.";
				p_lines.push_back(std::string(data, start, i - start));
			}
			comment = false;
			start = i + 1;
		}
	}
	if (start < length && comment == false)
	{
		if (length != (start + (i - start)))
			std::cout << "Index out of range.";
		std::string line = std::string(data, start, i - start);
		p_lines.push_back(line);
	}
	
	delete[] data;

	return true;
}

void readfile(Files& files, const char* p_filename)
{
	numberOfAttributes++;

	Lines lines;
	lines.push_back(p_filename);
	getFileLines(lines, p_filename);
	files.push_back(lines);
}

void parseFiles(Files& files)
{
	typedef std::map<std::string, std::map<std::string, std::string> > CombinedData;
	CombinedData combinedData;
	for (unsigned int i = 0; i < files.size(); ++i)
	{
		Strings lineOneParts;
		explode(lineOneParts, files[i][0], "/");
		std::string attributeName = lineOneParts[1].substr(0, lineOneParts[1].size() - 4);
		for (unsigned int j = 1; j < files[i].size(); j += 3)
		{
			Strings countryParts;
			explode(countryParts, files[i][j], "\t");
			std::string country = countryParts[countryParts.size() > 1 ? 1 : 0];
			std::string value = files[i][j + 1];

			// Erase the dollar sign.
			if (value[0] == '$')
			{
				value.erase(value.begin(), value.begin() + 2);
			}
			// Erase commas
			for (std::string::iterator it = value.begin(); it != value.end(); )
			{
				if ((*it) == ',')
				{
					it = value.erase(it);
				}
				else
				{
					++it;
				}
			}

			combinedData[country][attributeName] = value;
		}
	}

	int validCountryCount = 0;
	for (CombinedData::iterator it = combinedData.begin(); it != combinedData.end();)
	{
		if ((*it).second.size() == numberOfAttributes)
		{
			validCountryCount++;
			std::cout << "Added:   " << (*it).first << std::endl;
			++it;
		}
		else
		{
			std::cout << "Ignored: " << (*it).first <<std::endl;
			it = combinedData.erase(it);
		}
	}
	std::cout << validCountryCount << std::endl;

	// Write to file;
	std::ofstream outputFile("country data/real data.txt");

	for (std::map<std::string, std::string>::iterator it = (*combinedData.begin()).second.begin(); it != (*combinedData.begin()).second.end(); ++it)
	{
		outputFile << (*it).first << "\t";
	}
	outputFile << std::endl;

	for (CombinedData::iterator it = combinedData.begin(); it != combinedData.end(); ++it)
	{
		outputFile << (*it).first << "\t";
		for (std::map<std::string, std::string>::iterator it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2)
		{
			
			outputFile << (*it2).second << "\t";
		}
		outputFile << std::endl;
	}

	outputFile.close();

	std::ofstream outputFile2("country data/random data.txt");

	for (std::map<std::string, std::string>::iterator it = (*combinedData.begin()).second.begin(); it != (*combinedData.begin()).second.end(); ++it)
	{
		outputFile2 << (*it).first << "\t";
	}
	outputFile2 << std::endl;

	srand(static_cast<unsigned int>(time(0)));

	for (CombinedData::iterator it = combinedData.begin(); it != combinedData.end(); ++it)
	{
		outputFile2 << (*it).first << "\t";
		for (int i = 0; i < numberOfAttributes; i++)
		{
			outputFile2 << static_cast<float>(rand()) / RAND_MAX << "\t";
		}
		outputFile2 << std::endl;
	}

	outputFile2.close();
}

void openAllFiles()
{
	Files files;
	readfile(files, "country data/airports.txt");
	readfile(files, "country data/area.txt");
	readfile(files, "country data/birth rate.txt");
	readfile(files, "country data/current account balance.txt");
	readfile(files, "country data/death rate.txt");
	readfile(files, "country data/electricity consumption.txt");
	readfile(files, "country data/electricity production.txt");
	readfile(files, "country data/exports.txt");
	readfile(files, "country data/gdp per capita.txt");
	readfile(files, "country data/imports.txt");
	readfile(files, "country data/infant mortality rate.txt");
	readfile(files, "country data/internet hosts.txt");
	readfile(files, "country data/internet users.txt");
	readfile(files, "country data/labor force.txt");
	readfile(files, "country data/life expectancy at birth.txt");
	readfile(files, "country data/net migration rate.txt");
	readfile(files, "country data/population growth rate.txt");
	readfile(files, "country data/population.txt");
	readfile(files, "country data/roadways.txt");
	readfile(files, "country data/telephones main lines in use.txt");
	readfile(files, "country data/telephones mobile.txt");
	readfile(files, "country data/total fertility rate.txt");
	readfile(files, "country data/unemployment rate.txt");

	parseFiles(files);
}

void main()
{
	openAllFiles();
}